package com.wei.frame.mvp;

import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;

import com.wei.frame.utils.L;
import com.wei.frame.utils.Preconditions;

import java.lang.ref.WeakReference;

import javax.inject.Inject;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Action;
import io.reactivex.rxjava3.schedulers.Schedulers;


/**
 * 作者:赵若位
 * 时间:2020/8/20 3:06
 * 功能:
 */
public class BasePresenter<V extends IView, M extends IModel> implements LifecycleObserver {

    private V mView;
    private M mModel;
    private CompositeDisposable mDisposable;
    private WeakReference<V> mWeakReference;

    @Inject
    public BasePresenter(@Nullable V view, M model) {
        this.mView = Preconditions.checkNotNull(view, "%s cannot be null!",
                view.getClass().getSimpleName());
        this.mModel = model;
        onCreate();
    }

    public V getView() {
        return null != mWeakReference ? mWeakReference.get() : null;
    }

    public M getModel() {
        return mModel;
    }

    private void onCreate() {
        L.i(getClass().getSimpleName() + "开始执行onCreate");
        if (null != mView) {
            mWeakReference = new WeakReference<>(mView);
        }
        if (null != mView && mView instanceof LifecycleOwner) {
            ((LifecycleOwner) mView).getLifecycle().addObserver(this);
        }
    }

    /**
     * 注意, 如果在这里调用了 {@link #onDestroy(LifecycleOwner)} 方法, 会出现某些地方引用 {@code mModel} 或 {@code mRootView} 为 null 的情况
     * 比如在 {@link com.trello.rxlifecycle4.RxLifecycle} 终止 {@link io.reactivex.rxjava3.core.Observable} 时,
     * 在 {@link io.reactivex.rxjava3.core.Observable#doFinally(Action)} ()} 中却引用了 {@code mRootView} 做一些释放资源的操作, 此时会空指针
     * 或者如果你声明了多个 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 时在其他 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
     * 中引用了 {@code mModel} 或 {@code mRootView} 也可能会出现此情况
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy(LifecycleOwner owner) {
        L.e(getClass().getSimpleName() + "->开始执行解除绑定");
        unDisposable();
        if (null != mWeakReference) {
            mWeakReference.clear();
            mWeakReference = null;
        }
        this.mView = null;
        if (null != mModel) {
            mModel.onDestroy();
        }
        if (null != owner) {
            owner.getLifecycle().removeObserver(this);
        }
    }

    protected final void addDisposable(@Nullable Disposable disposable) {
        if (null == mDisposable) {
            mDisposable = new CompositeDisposable();
        }
        if (null != disposable) {
            mDisposable.add(disposable);
        }
    }

    protected final void unDisposable() {
        if (null != mDisposable) {
            mDisposable.dispose();
            mDisposable.clear();
            mDisposable = null;
        }
    }

    /**
     * 对{@link #single(Single, boolean)}和{@link #single(Single)}进行封装
     * 主要是对线程切换，内存泄露以及进度条的封装
     */
    protected <T> Single<T> single(Single<T> single, boolean isLoading) {
        Preconditions.checkNotNull(single, "The Single of %s is empty!", getClass().getSimpleName());
        return single.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(disposable -> {
                    addDisposable(disposable);
                    if (isLoading && null != getView()) {
                        getView().showLoading();
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .doFinally(() -> {
                    if (isLoading && null != getView()) {
                        getView().hideLoading();
                    }
                })
                .unsubscribeOn(Schedulers.io())
                .compose(getView().bindRxLifecycle());
    }

    protected <T> Single<T> single(Single<T> single) {
        return single(single, true);
    }


    protected <T> Observable<T> observable(Observable<T> observable, boolean isLoading) {
        Preconditions.checkNotNull(observable, "The Single of %s is empty!", getClass().getSimpleName());
        return observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(disposable -> {
                    addDisposable(disposable);
                    if (isLoading && null != getView()) {
                        getView().showLoading();
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .doFinally(() -> {
                    if (isLoading && null != getView()) {
                        getView().hideLoading();
                    }
                })
                .unsubscribeOn(Schedulers.io())
                .compose(getView().bindRxLifecycle());
    }
}
